package com.tempjob.common.local;

import com.alibaba.fastjson.JSON;
import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.tempjob.common.businesss.mongo.entity.*;
import com.tempjob.common.businesss.mongo.service.*;
import com.tempjob.common.model.AreaVO;
import com.tempjob.common.model.QueryAreaDTO;
import com.tempjob.common.utils.CachedBeanCopier;
import com.tempjob.common.vo.admin.AreaListVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author hui
 * @Date 21-9-13 下午2:36
 **/
@Service
public class LocalAreaService {

    @Autowired
    private RegionProvinceService provinceService;

    @Autowired
    private RegionCityService cityService;

    @Autowired
    private RegionAreaService areaService;

    @Autowired
    private RegionStreetService streetService;

    @Autowired
    private RegionRoadService roadService;

    //社区
    @Autowired
    private RegionCommunityService communityService;

    //小区
    @Autowired
    private RegionEstateService estateService;

    private LoadingCache<String, List<AreaVO>> provinceList = CacheBuilder.newBuilder().maximumSize(5000)
            .expireAfterWrite(3, TimeUnit.DAYS).build(new CacheLoader<String, List<AreaVO>>() {
                @Override
                public List<AreaVO> load(String code) throws Exception {
                    List<RegionProvince> list = provinceService.list();
                    List<AreaVO> voList = new ArrayList<>();
                    if (list != null && !list.isEmpty()) {
                        CachedBeanCopier.copyList(list, voList, AreaVO.class);
                    }
                    return voList;
                }
            });

    private LoadingCache<String, List<AreaVO>> cityList = CacheBuilder.newBuilder().maximumSize(5000)
            .expireAfterWrite(3, TimeUnit.DAYS).build(new CacheLoader<String, List<AreaVO>>() {
                @Override
                public List<AreaVO> load(String code) throws Exception {
                    QueryAreaDTO dto = JSON.parseObject(code, QueryAreaDTO.class);
                    LambdaQueryChainWrapper<RegionCity> query = cityService.lambdaQuery();
                    if (dto.getProvince() != null) {
                        query.eq(RegionCity::getProvinceCode, dto.getProvince());
                    }
                    List<RegionCity> list = cityService.list(query);
                    List<AreaVO> voList = new ArrayList<>();
                    if (list != null && !list.isEmpty()) {
                        CachedBeanCopier.copyList(list, voList, AreaVO.class);
                    }
                    return voList;
                }
            });

    private LoadingCache<String, List<AreaVO>> areaList = CacheBuilder.newBuilder().maximumSize(5000)
            .expireAfterWrite(3, TimeUnit.DAYS).build(new CacheLoader<String, List<AreaVO>>() {
                @Override
                public List<AreaVO> load(String code) throws Exception {
                    QueryAreaDTO dto = JSON.parseObject(code, QueryAreaDTO.class);
                    LambdaQueryChainWrapper<RegionArea> query = areaService.lambdaQuery();
                    if (dto.getProvince() != null) {
                        query.eq(RegionArea::getProvinceCode, dto.getProvince());
                    }
                    if (dto.getCity() != null) {
                        query.eq(RegionArea::getCityCode, dto.getCity());
                    }
                    List<RegionArea> list = areaService.list(query);
                    List<AreaVO> voList = new ArrayList<>();
                    if (list != null && !list.isEmpty()) {
                        CachedBeanCopier.copyList(list, voList, AreaVO.class);
                    }
                    return voList;
                }
            });

    /**
     * 省市区树形列表
     */
    private LoadingCache<String, List<AreaListVO>> allAreaList = CacheBuilder.newBuilder().maximumSize(50)
            .expireAfterWrite(3, TimeUnit.DAYS).build(new CacheLoader<String, List<AreaListVO>>() {
                @Override
                public List<AreaListVO> load(String code) throws Exception {
                    List<AreaVO> provinces = getProvince();
                    ArrayList<AreaListVO> vos = new ArrayList<>();
                    for (AreaVO p : provinces) {
                        AreaListVO vo = new AreaListVO();
                        vo.setCode(p.getCode());
                        vo.setName(p.getName());
                        vo.setInitials(p.getInitials());
                        List<AreaVO> citys = getCity(new QueryAreaDTO(p.getCode(), null, null));
                        ArrayList<AreaListVO> chirld = null;
                        for (AreaVO c : citys) {
                            if (chirld == null) {
                                chirld = new ArrayList<>();
                            }
                            AreaListVO cvo = new AreaListVO();
                            cvo.setCode(c.getCode());
                            cvo.setName(c.getName());
                            cvo.setInitials(c.getInitials());
                            List<AreaVO> areas = getArea(new QueryAreaDTO(p.getCode(), c.getCode(), null));
                            ArrayList<AreaListVO> cChild = null;
                            for (AreaVO a : areas) {
                                if (cChild == null) {
                                    cChild = new ArrayList<>();
                                }
                                AreaListVO avo = new AreaListVO();
                                avo.setCode(a.getCode());
                                avo.setName(a.getName());
                                avo.setInitials(a.getInitials());
                                cChild.add(avo);
                            }
                            cvo.setChildren(cChild);
                            chirld.add(cvo);
                        }
                        vo.setChildren(chirld);
                        vos.add(vo);
                    }
                    return vos;
                }
            });

    private LoadingCache<String, List<AreaVO>> streetList = CacheBuilder.newBuilder().maximumSize(5000)
            .expireAfterWrite(3, TimeUnit.DAYS).build(new CacheLoader<String, List<AreaVO>>() {
                @Override
                public List<AreaVO> load(String code) throws Exception {
                    QueryAreaDTO dto = JSON.parseObject(code, QueryAreaDTO.class);
                    LambdaQueryChainWrapper<RegionStreet> query = streetService.lambdaQuery();
                    if (dto.getProvince() != null) {
                        query.eq(RegionStreet::getProvinceCode, dto.getProvince());
                    }
                    if (dto.getCity() != null) {
                        query.eq(RegionStreet::getCityCode, dto.getCity());
                    }
                    if (dto.getArea() != null) {
                        query.eq(RegionStreet::getAreaCode, dto.getArea());
                    }
                    List<RegionStreet> list = streetService.list(query);
                    List<AreaVO> voList = new ArrayList<>();
                    if (list != null && !list.isEmpty()) {
                        CachedBeanCopier.copyList(list, voList, AreaVO.class);
                    }
                    return voList;
                }
            });

    private LoadingCache<Long, List<RegionStreet>> streetInfoList = CacheBuilder.newBuilder().maximumSize(5000)
            .expireAfterWrite(3, TimeUnit.DAYS).build(new CacheLoader<Long, List<RegionStreet>>() {
                @Override
                public List<RegionStreet> load(Long code) throws Exception {
                    LambdaQueryChainWrapper<RegionStreet> query = streetService.lambdaQuery().eq(RegionStreet::getAreaCode, code);
                    return streetService.list(query);
                }
            });


    public List<RegionStreet> getJnqStreetList() {
        return this.streetInfoList.getUnchecked(510106L);
    }

    private LoadingCache<Long, AreaVO> street = CacheBuilder.newBuilder().maximumSize(5000)
            .expireAfterWrite(3, TimeUnit.MINUTES).build(new CacheLoader<Long, AreaVO>() {
                @Override
                public AreaVO load(Long code) throws Exception {
                    LambdaQueryChainWrapper<RegionStreet> query = streetService.lambdaQuery();
                    query.eq(RegionStreet::getCode, code);
                    RegionStreet street = streetService.one(query);
                    AreaVO voList = new AreaVO();
                    if (street != null) {
                        CachedBeanCopier.copyObject(street, voList);
                    }
                    return voList;
                }
            });

    private LoadingCache<Long, AreaVO> community = CacheBuilder.newBuilder().maximumSize(5000)
            .expireAfterWrite(3, TimeUnit.MINUTES).build(new CacheLoader<Long, AreaVO>() {
                @Override
                public AreaVO load(Long code) throws Exception {
                    LambdaQueryChainWrapper<RegionCommunity> query = communityService.lambdaQuery();
                    query.eq(RegionCommunity::getCode, code);
                    RegionCommunity street = communityService.one(query);
                    AreaVO voList = new AreaVO();
                    if (street != null) {
                        CachedBeanCopier.copyObject(street, voList);
                    }
                    return voList;
                }
            });

    private LoadingCache<String, List<AreaVO>> roadList = CacheBuilder.newBuilder().maximumSize(5000)
            .expireAfterWrite(3, TimeUnit.DAYS).build(new CacheLoader<String, List<AreaVO>>() {
                @Override
                public List<AreaVO> load(String code) throws Exception {
                    QueryAreaDTO dto = JSON.parseObject(code, QueryAreaDTO.class);
                    LambdaQueryChainWrapper<RegionRoad> query = roadService.lambdaQuery();
                    if (dto.getProvince() != null) {
                        query.eq(RegionRoad::getProvinceCode, dto.getProvince());
                    }
                    if (dto.getCity() != null) {
                        query.eq(RegionRoad::getCityCode, dto.getCity());
                    }
                    if (dto.getArea() != null) {
                        query.eq(RegionRoad::getAreaCode, dto.getArea());
                    }
                    if (dto.getStreet() != null) {
                        query.eq(RegionRoad::getStreetCode, dto.getStreet());
                    }
                    List<RegionRoad> list = roadService.list(query);
                    List<AreaVO> voList = new ArrayList<>();
                    if (list != null && !list.isEmpty()) {
                        CachedBeanCopier.copyList(list, voList, AreaVO.class);
                    }
                    return voList;
                }
            });


    private LoadingCache<String, List<AreaVO>> communityList = CacheBuilder.newBuilder().maximumSize(5000)
            .expireAfterWrite(3, TimeUnit.DAYS).build(new CacheLoader<String, List<AreaVO>>() {
                @Override
                public List<AreaVO> load(String code) throws Exception {
                    QueryAreaDTO dto = JSON.parseObject(code, QueryAreaDTO.class);
                    LambdaQueryChainWrapper<RegionCommunity> query = communityService.lambdaQuery();
                    if (dto.getProvince() != null) {
                        query.eq(RegionCommunity::getProvinceCode, dto.getProvince());
                    }
                    if (dto.getCity() != null) {
                        query.eq(RegionCommunity::getCityCode, dto.getCity());
                    }
                    if (dto.getArea() != null) {
                        query.eq(RegionCommunity::getAreaCode, dto.getArea());
                    }
                    if (dto.getStreet() != null) {
                        query.eq(RegionCommunity::getStreetCode, dto.getStreet());
                    }
                    List<RegionCommunity> list = communityService.list(query);
                    List<AreaVO> voList = new ArrayList<>();
                    if (list != null && !list.isEmpty()) {
                        CachedBeanCopier.copyList(list, voList, AreaVO.class);
                    }
                    return voList;
                }
            });

    private LoadingCache<String, List<AreaVO>> estateList = CacheBuilder.newBuilder().maximumSize(5000)
            .expireAfterWrite(3, TimeUnit.DAYS).build(new CacheLoader<String, List<AreaVO>>() {
                @Override
                public List<AreaVO> load(String code) throws Exception {
                    QueryAreaDTO dto = JSON.parseObject(code, QueryAreaDTO.class);
                    LambdaQueryChainWrapper<RegionEstate> query = estateService.lambdaQuery();
                    if (dto.getProvince() != null) {
                        query.eq(RegionEstate::getProvinceCode, dto.getProvince());
                    }
                    if (dto.getCity() != null) {
                        query.eq(RegionEstate::getCityCode, dto.getCity());
                    }
                    if (dto.getArea() != null) {
                        query.eq(RegionEstate::getAreaCode, dto.getArea());
                    }
                    if (dto.getStreet() != null) {
                        query.eq(RegionEstate::getStreetCode, dto.getStreet());
                    }
                    if (dto.getCommunity() != null) {
                        query.eq(RegionEstate::getCommunityCode, dto.getCommunity());
                    }
                    List<RegionEstate> list = estateService.list(query);
                    List<AreaVO> voList = new ArrayList<>();
                    if (list != null && !list.isEmpty()) {
                        CachedBeanCopier.copyList(list, voList, AreaVO.class);
                    }
                    return voList;
                }
            });

    /**
     * 获取省列表
     *
     * @return
     */
    public List<AreaVO> getProvince() {
        return this.provinceList.getUnchecked("");
    }

    /**
     * 获取市
     *
     * @param dto
     * @return
     */
    public List<AreaVO> getCity(QueryAreaDTO dto) {
        return this.cityList.getUnchecked(JSON.toJSONString(dto));
    }

    /**
     * 获取区
     *
     * @param dto
     * @return
     */
    public List<AreaVO> getArea(QueryAreaDTO dto) {
        return this.areaList.getUnchecked(JSON.toJSONString(dto));
    }

    /**
     * 获取道路
     *
     * @param dto
     * @return
     */
    public List<AreaVO> getRoad(QueryAreaDTO dto) {
        return this.roadList.getUnchecked(JSON.toJSONString(dto));
    }

    /**
     * 获取社区
     *
     * @param dto
     * @return
     */
    public List<AreaVO> getCommunity(QueryAreaDTO dto) {
        return this.communityList.getUnchecked(JSON.toJSONString(dto));
    }

    /**
     * 获取街道
     *
     * @param dto
     * @return
     */
    public List<AreaVO> getStreet(QueryAreaDTO dto) {
        return this.streetList.getUnchecked(JSON.toJSONString(dto));
    }

    public AreaVO getStreetByCode(Long code) {
        return this.street.getUnchecked(code);
    }

    public AreaVO getCommunitytByCode(Long code) {
        return this.community.getUnchecked(code);
    }

    /**
     * 获取小区
     *
     * @param dto
     * @return
     */
    public List<AreaVO> getEstate(QueryAreaDTO dto) {
        return this.estateList.getUnchecked(JSON.toJSONString(dto));
    }

    /**
     * 删除社区缓存
     */
    public void delCommunity() {
        this.communityList.invalidateAll();
    }

    /**
     * 删除道路缓存
     */
    public void delRoad() {
        this.roadList.invalidateAll();
    }

    /**
     * 删除街道缓存
     */
    public void delStreet() {
        this.streetList.invalidateAll();
    }

    /**
     * 删除小区缓存
     */
    public void delEstate() {
        this.estateList.invalidateAll();
    }

    public List<AreaListVO> getAllAreaList() {
        return this.allAreaList.getUnchecked("");
    }


}
